package net.minecraft.src;

import java.util.Random;

public class BlockRail extends Block
{
    private final boolean isPowered;
    
    /**
     * Forge: Moved render type to a field and a setter.
     * This allows for a mod to change the render type
     * for vanilla rails, and any mod rails that extend
     * this class.
     */
    private int renderType = 9;
    
    public void setRenderType(int value)
    {
    	renderType = value;
    }

    public static final boolean isRailBlockAt(World world, int i, int j, int k)
    {
        int l = world.getBlockId(i, j, k);
        return Block.blocksList[l] instanceof BlockRail;
    }

    public static final boolean isRailBlock(int i)
    {
    	return Block.blocksList[i] instanceof BlockRail;
    }

    protected BlockRail(int i, int j, boolean flag)
    {
        super(i, j, Material.circuits);
        isPowered = flag;
        setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
    }

    public boolean isPowered()
    {
        return isPowered;
    }

    public AxisAlignedBB getCollisionBoundingBoxFromPool(World world, int i, int j, int k)
    {
        return null;
    }

    public boolean isOpaqueCube()
    {
        return false;
    }

    public MovingObjectPosition collisionRayTrace(World world, int i, int j, int k, Vec3D vec3d, Vec3D vec3d1)
    {
        setBlockBoundsBasedOnState(world, i, j, k);
        return super.collisionRayTrace(world, i, j, k, vec3d, vec3d1);
    }

    public void setBlockBoundsBasedOnState(IBlockAccess iblockaccess, int i, int j, int k)
    {
        int l = iblockaccess.getBlockMetadata(i, j, k);
        if (l >= 2 && l <= 5)
        {
            setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F);
        }
        else
        {
            setBlockBounds(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
        }
    }

    public int getBlockTextureFromSideAndMetadata(int i, int j)
    {
        if (isPowered)
        {
            if (blockID == Block.railPowered.blockID && (j & 8) == 0)
            {
                return blockIndexInTexture - 16;
            }
        }
        else if (j >= 6)
        {
            return blockIndexInTexture - 16;
        }
        return blockIndexInTexture;
    }

    public boolean renderAsNormalBlock()
    {
        return false;
    }

    public int getRenderType()
    {
        return renderType;
    }

    public int quantityDropped(Random random)
    {
        return 1;
    }

    public boolean canPlaceBlockAt(World world, int i, int j, int k)
    {
        return world.isBlockSolidOnSide(i, j - 1, k, 1);
    }

    public void onBlockAdded(World world, int i, int j, int k)
    {
        if (!world.isRemote)
        {
            refreshTrackShape(world, i, j, k, true);
            if (blockID == Block.railPowered.blockID)
            {
                onNeighborBlockChange(world, i, j, k, blockID);
            }
        }
    }

    public void onNeighborBlockChange(World world, int i, int j, int k, int l)
    {
        if (world.isRemote)
        {
            return;
        }
        int i1 = world.getBlockMetadata(i, j, k);
        int j1 = i1;
        if (isPowered)
        {
            j1 &= 7;
        }
        boolean flag = false;
        if (!world.isBlockSolidOnSide(i, j - 1, k, 1))
        {
            flag = true;
        }
        if (j1 == 2 && !world.isBlockSolidOnSide(i + 1, j, k, 1))
        {
            flag = true;
        }
        if (j1 == 3 && !world.isBlockSolidOnSide(i - 1, j, k, 1))
        {
            flag = true;
        }
        if (j1 == 4 && !world.isBlockSolidOnSide(i, j, k - 1, 1))
        {
            flag = true;
        }
        if (j1 == 5 && !world.isBlockSolidOnSide(i, j, k + 1, 1))
        {
            flag = true;
        }
        if (flag)
        {
            dropBlockAsItem(world, i, j, k, world.getBlockMetadata(i, j, k), 0);
            world.setBlockWithNotify(i, j, k, 0);
        }
        else if (blockID == Block.railPowered.blockID)
        {
            boolean flag1 = world.isBlockIndirectlyGettingPowered(i, j, k) || world.isBlockIndirectlyGettingPowered(i, j + 1, k);
            flag1 = flag1 || isNeighborRailPowered(world, i, j, k, i1, true, 0) || isNeighborRailPowered(world, i, j, k, i1, false, 0);
            boolean flag2 = false;
            if (flag1 && (i1 & 8) == 0)
            {
                world.setBlockMetadataWithNotify(i, j, k, j1 | 8);
                flag2 = true;
            }
            else if (!flag1 && (i1 & 8) != 0)
            {
                world.setBlockMetadataWithNotify(i, j, k, j1);
                flag2 = true;
            }
            if (flag2)
            {
                world.notifyBlocksOfNeighborChange(i, j - 1, k, blockID);
                if (j1 == 2 || j1 == 3 || j1 == 4 || j1 == 5)
                {
                    world.notifyBlocksOfNeighborChange(i, j + 1, k, blockID);
                }
            }
        }
        else if (l > 0 && Block.blocksList[l].canProvidePower() && !isPowered && RailLogic.getNAdjacentTracks(new RailLogic(this, world, i, j, k)) == 3)
        {
            refreshTrackShape(world, i, j, k, false);
        }
    }

    private void refreshTrackShape(World world, int i, int j, int k, boolean flag)
    {
        if (world.isRemote)
        {
            return;
        }
        else
        {
            (new RailLogic(this, world, i, j, k)).refreshTrackShape(world.isBlockIndirectlyGettingPowered(i, j, k), flag);
            return;
        }
    }

    private boolean isNeighborRailPowered(World world, int i, int j, int k, int l, boolean flag, int i1)
    {
        if (i1 >= 8)
        {
            return false;
        }
        int j1 = l & 7;
        boolean flag1 = true;
        switch (j1)
        {
            case 0:
                if (flag)
                {
                    k++;
                }
                else
                {
                    k--;
                }
                break;

            case 1:
                if (flag)
                {
                    i--;
                }
                else
                {
                    i++;
                }
                break;

            case 2:
                if (flag)
                {
                    i--;
                }
                else
                {
                    i++;
                    j++;
                    flag1 = false;
                }
                j1 = 1;
                break;

            case 3:
                if (flag)
                {
                    i--;
                    j++;
                    flag1 = false;
                }
                else
                {
                    i++;
                }
                j1 = 1;
                break;

            case 4:
                if (flag)
                {
                    k++;
                }
                else
                {
                    k--;
                    j++;
                    flag1 = false;
                }
                j1 = 0;
                break;

            case 5:
                if (flag)
                {
                    k++;
                    j++;
                    flag1 = false;
                }
                else
                {
                    k--;
                }
                j1 = 0;
                break;
        }
        if (isRailPassingPower(world, i, j, k, flag, i1, j1))
        {
            return true;
        }
        return flag1 && isRailPassingPower(world, i, j - 1, k, flag, i1, j1);
    }

    private boolean isRailPassingPower(World world, int i, int j, int k, boolean flag, int l, int i1)
    {
        int j1 = world.getBlockId(i, j, k);
        if (j1 == Block.railPowered.blockID)
        {
            int k1 = world.getBlockMetadata(i, j, k);
            int l1 = k1 & 7;
            if (i1 == 1 && (l1 == 0 || l1 == 4 || l1 == 5))
            {
                return false;
            }
            if (i1 == 0 && (l1 == 1 || l1 == 2 || l1 == 3))
            {
                return false;
            }
            if ((k1 & 8) != 0)
            {
                if (world.isBlockIndirectlyGettingPowered(i, j, k) || world.isBlockIndirectlyGettingPowered(i, j + 1, k))
                {
                    return true;
                }
                else
                {
                    return isNeighborRailPowered(world, i, j, k, k1, flag, l + 1);
                }
            }
        }
        return false;
    }

    public int getMobilityFlag()
    {
        return 0;
    }

    /**
     * This function is no longer called by Minecraft
     */
    @Deprecated
    static boolean isPoweredBlockRail(BlockRail blockrail)
    {
        return blockrail.isPowered;
    }
    
    /**
     * Return true if the rail can make corners.
     * Used by placement logic.
     * @param world The world.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     * @return True if the rail can make corners.
     */
    public boolean isFlexibleRail(World world, int i, int j, int k)
    {
        return !isPowered;
    }

    /**
     * Returns true if the rail can make up and down slopes.
     * Used by placement logic.
     * @param world The world.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     * @return True if the rail can make slopes.
     */
    public boolean canMakeSlopes(World world, int i, int j, int k)
    {
        return true;
    }

    /**
     * Return the rails metadata (without the power bit if the rail uses one).
     * Can be used to make the cart think the rail something other than it is,
     * for example when making diamond junctions or switches.
     * The cart parameter will often be null unless it it called from EntityMinecart.
     * 
     * Valid rail metadata is defined as follows:
     * 0x0: flat track going North-South
     * 0x1: flat track going West-East
     * 0x2: track ascending to the East
     * 0x3: track ascending to the West
     * 0x4: track ascending to the North
     * 0x5: track ascending to the South
     * 0x6: WestNorth corner (connecting East and South)
     * 0x7: EastNorth corner (connecting West and South)
     * 0x8: EastSouth corner (connecting West and North)
     * 0x9: WestSouth corner (connecting East and North)
     * 
     * All directions are Notch defined.
     * In MC Beta 1.8.3 the Sun rises in the North.
     * In MC 1.0.0 the Sun rises in the East.
     * @param world The world.
     * @param cart The cart asking for the metadata, null if it is not called by EntityMinecart.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     * @return The metadata.
     */
    public int getBasicRailMetadata(IBlockAccess world, EntityMinecart cart, int i, int j, int k)
    {
        int meta = world.getBlockMetadata(i, j, k);
        if(isPowered) {
            meta = meta & 7;
        }
        return meta;
    }
	 
    /**
     * Returns the max speed of the rail at [i, j, k].
     * @param world The world.
     * @param cart The cart on the rail, may be null.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     * @return The max speed of the current rail.
     */
    public float getRailMaxSpeed(World world, EntityMinecart cart, int i, int j, int k)
    {
        return 0.4f;
    }
	 
    /**
     * This function is called by any minecart that passes over this rail.
     * It is called once per update tick that the minecart is on the rail.
     * @param world The world.
     * @param cart The cart on the rail.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     */
    public void onMinecartPass(World world, EntityMinecart cart, int i, int j, int k)
    {
    }
    
    /**
     * Return true if this rail uses the 4th bit as a power bit.
     * Avoid using this function when getBasicRailMetadata() can be used instead.
     * The only reason to use this function is if you wish to change the rails metadata.
     * @param world The world.
     * @param i The rail X coordinate.
     * @param j The rail Y coordinate.
     * @param k The rail Z coordinate.
     * @return True if the 4th bit is a power bit.
     */
    public boolean hasPowerBit(World world, int i, int j, int k)
    {
        return isPowered;
    }
}
